home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UDiscListView.cp < prev    next >
Encoding:
Text File  |  1994-03-06  |  24.5 KB  |  507 lines  |  [TEXT/MPS ]

  1. // Copyright © 1992 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // UDiscListView.cp
  3.  
  4. #include "UDiscListView.h"
  5. #include "UDiscList.h"
  6. #include "UDiscListCmds.h"
  7. #include "UBinariesCmds.h"
  8. #include "UPostArticleCmds.h"
  9. #include "NetAsciiTools.h"
  10. #include "UNewsAppl.h"
  11. #include "UGroupDoc.h"
  12. #include "UThread.h"
  13. #include "UPrefsDatabase.h"
  14. #include "URowSelection.h"
  15. #include "UTextScroller.h"
  16. #include "ViewTools.h"
  17. #include "Tools.h"
  18.  
  19. #include <RsrcGlobals.h>
  20. #include <ErrorGlobals.h>
  21.  
  22. #include <Packages.h>
  23. #include <ToolUtils.h>
  24.  
  25. #pragma segment MyGroup
  26.  
  27. #define qPrintDottedLine 1
  28.  
  29. #define qDebugArticleIterator qDebug & 0
  30.  
  31. //-------------------------------------------------------------------
  32. const short kSeparatorHeight = 2; // should be in 'View'
  33. const short kExtraHeight = 2;
  34.  
  35. CStr255 gNewString, gSeenString, gReadString, gExpiredSubjectString, gExpiredAuthorString;
  36. Boolean gHasFetchedStatusStrings = false;
  37.  
  38. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  39. class CDiscListArticleIterator : public CIterator
  40. {
  41.     public:
  42.         CDiscListArticleIterator(TDiscListView *dlv, GridCell cell);
  43.         ~CDiscListArticleIterator();
  44.         
  45.         long FirstArticleID();
  46.         Boolean More();
  47.         long NextArticleID();
  48.         ArrayIndex GetIndex();
  49.         Boolean ArticleIsAvaible();
  50.         
  51.         void GetArticleVRects(CRect &subjectRect, CRect &statusRect, CRect &authorRect);
  52.     protected:
  53.         void Advance();
  54.  
  55.     private:
  56.         TDiscListView *fDiscListView;
  57.         PDiscList *fDiscList;
  58.         ArrayIndex fDiscIndex;
  59.         ArrayIndex fNoArticles, fArticleIndex;
  60.         long fArticleID;
  61.         CRect fCellRect;
  62. };
  63.  
  64. CDiscListArticleIterator::CDiscListArticleIterator(TDiscListView *dlv, GridCell cell)
  65. {
  66.     fDiscListView = dlv;
  67.     fDiscList = dlv->fDiscList;
  68.     VRect vr;
  69.     dlv->CellToVRect(cell, vr);
  70.     dlv->ViewToQDRect(vr, fCellRect);
  71.     fDiscIndex = dlv->fDiscIndexList->At(cell.v);
  72.     fNoArticles = fDiscList->GetNoArticles(fDiscIndex);
  73. #if qDebugArticleIterator
  74.     fprintf(stderr, "DLAI: Constructor, cellRect = %s, discIndex = %ld, noArticles = %ld\n", (char*)fCellRect, fDiscIndex, fNoArticles);
  75. #endif
  76. }
  77.  
  78. CDiscListArticleIterator::~CDiscListArticleIterator()
  79. {
  80. #if qDebugArticleIterator
  81.     fprintf(stderr, "DLAI: Destruct\n");
  82. #endif
  83. }
  84.  
  85. long CDiscListArticleIterator::FirstArticleID()
  86. {
  87.     fArticleIndex = 0;
  88.     Advance();
  89. #if qDebugArticleIterator
  90.     fprintf(stderr, "DLAI: returned %ld as first article id\n", fArticleID);
  91. #endif
  92.     return fArticleID;
  93. }
  94.  
  95. Boolean CDiscListArticleIterator::More()
  96. {
  97.     return fArticleIndex <= fNoArticles;
  98. }
  99.  
  100. long CDiscListArticleIterator::NextArticleID()
  101. {
  102.     if (More())
  103.         Advance();
  104. #if qDebugArticleIterator
  105.     fprintf(stderr, "DLAI: returns %ld as next article id\n", fArticleID);
  106. #endif
  107.     return fArticleID;
  108. }
  109.  
  110. void CDiscListArticleIterator::Advance()
  111. {
  112.     ++fArticleIndex;
  113.     if (!More())
  114.         return;
  115.     fArticleID = fDiscList->GetArticleID(fDiscIndex, fArticleIndex);
  116. #if qDebugArticleIterator
  117.     fprintf(stderr, "DLAI: Advance: new fArticleIndex = %ld, new fArticleID = %ld\n", fArticleIndex, fArticleID);
  118. #endif
  119. }
  120.  
  121. ArrayIndex CDiscListArticleIterator::GetIndex()
  122. {
  123. #if qDebugArticleIterator
  124.     fprintf(stderr, "DLAI: GetIndex() returns %ld\n", fArticleIndex);
  125. #endif
  126.     return fArticleIndex;
  127. }
  128.  
  129. Boolean CDiscListArticleIterator::ArticleIsAvaible()
  130. {
  131.     return fArticleID >= fDiscListView->fFirstAvaibleID && fArticleID <= fDiscListView->fLastAvaibleID;
  132. }
  133.     
  134. void CDiscListArticleIterator::GetArticleVRects(CRect &subjectRect, CRect &statusRect, CRect &authorRect)
  135. {
  136.     short top = fCellRect.top + kSeparatorHeight;
  137.     top += (short(fArticleIndex) - 1) * fDiscListView->fGridViewTextStyle.fRowHeight;
  138.     short bottom = top + fDiscListView->fGridViewTextStyle.fRowHeight;
  139.     subjectRect.top = statusRect.top = authorRect.top = top;
  140.     subjectRect.bottom = statusRect.bottom = authorRect.bottom = bottom;
  141.     
  142.     short h = fDiscListView->fGridViewTextStyle.fHorzOffset;
  143.     short col1 = h;
  144.     short col2 = col1 + fDiscListView->fSubjectWidth;
  145.     short col3 = col2 + 2 * h;
  146.     subjectRect.left = col1;
  147.     subjectRect.right = col2 - h;
  148.     if (fArticleIndex > 1)
  149.         subjectRect.left += fDiscListView->fSubjectHorzOffset;
  150.     statusRect.left = col2;
  151.     statusRect.right = col3;
  152.     authorRect.left = col3;
  153.     authorRect.right = short(fDiscListView->fSize.h);
  154. #if qDebugArticleIterator
  155.     fprintf(stderr, "DLAI: GetRects, subject = %s, ", (char*)subjectRect);
  156.     fprintf(stderr, "status = %s, ", (char*)statusRect);
  157.     fprintf(stderr, "author = %s\n", (char*)authorRect);
  158. #endif
  159. }
  160.  
  161. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  162. TDiscListView::TDiscListView()
  163. {
  164. }
  165.  
  166. pascal void TDiscListView::Initialize()
  167. {
  168.     inherited::Initialize();
  169.     fDoc = nil;
  170.     fWindow = nil;
  171.     fArticleStcleSeen); // test
  172.  
  173.         HandleOffsetLength hol;
  174.         CStr255 subject("");
  175.         if (fDoc->GetSubject(id, hol))
  176.             CopyHolToCStr255(hol, subject);
  177.         
  178.         short i = subject.Length();
  179.         while (i && subject[i] <= 32)
  180.             --i;
  181.         subject.Length() = i;
  182.         while (i && subject[1] <= 32)
  183.         {
  184.             subject.Delete(1, 1); // expensive but seldom
  185.             --i;
  186.         }
  187.  
  188.         Boolean drawSubject;
  189.         if (iter.GetIndex() == 1)
  190.             drawSubject = true;
  191.         else
  192.         {
  193.             drawSubject = (subject != lastSubject);
  194.             if (drawSubject)
  195.             {
  196.                 if (subject.Length() > 4 && subject[1] == 'R' && subject[2] == 'e' && subject[3] == ':')
  197.                 {
  198.                     i = (subject[4] == 32) ? 5 : 4;
  199.                     while (subject.Length() >= 5 && subject[5] <= 32)
  200.                         subject.Delete(5, 1);
  201.                     if (
  202.                         subject.Length() == lastSubject.Length() + 4 && 
  203.                         EqualBlocks(Ptr(&subject[5]), Ptr(&lastSubject[1]), lastSubject.Length()))
  204.                     {
  205.                             drawSubject = false; // ignore "Re: "
  206.                     }
  207.                     else if (
  208.                         subject.Length() + 4 == lastSubject.Length() &&
  209.                         EqualBlocks(Ptr(&subject[1]), Ptr(&lastSubject[5]), subject.Length()))
  210.                     {
  211.                         drawSubject = false; // ignore removed "Re: "
  212.                     }
  213.                 }
  214.             }
  215.         }
  216.  
  217.         lastSubject = subject;
  218.         if (drawSubject)
  219.         {
  220.             MoveTo(subjectRect.left, v);
  221.             TruncString(subjectRect.GetLength(hSel), subject, smTruncMiddle);
  222.             DrawString(subject);
  223.         }
  224.         
  225.         MoveTo(statusRect.left, v);
  226.         ArticleStatus stat = fOldArticleStatus->GetStatus(id);
  227. //        ArticleStatus stat = fArticleStatus->GetStatus(id);
  228.         if (stat == kArticleNew)
  229.             DrawString(gNewString);
  230.         else if (stat == kArticleSeen)
  231.             DrawString(gSeenString);
  232.         else
  233.             DrawString(gReadString);
  234.  
  235.         MoveTo(authorRect.left, v);
  236.         CStr255 email;
  237.         if (fDoc->GetFrom(id, hol))
  238.         {
  239.             CStr255 text;
  240.             CopyHolToCStr255(hol, text);
  241.             GetPrintableAuthorName(text, s, email);
  242.         }
  243.         else
  244.             s = gExpiredAuthorString;
  245.         DrawString(s);
  246. #if qDebug
  247.         DrawString(", ");
  248.         NumToString(id, s);
  249.         DrawString(s);
  250. #endif
  251.     }
  252. }
  253.  
  254. pascal void TDiscListView::DrawRangeOfCells(GridCell startCell,
  255.                                         GridCell stopCell,
  256.                                         const VRect &aRect)
  257. {
  258.     TextStyle itsTextStyle = fGridViewTextStyle.fTextStyle;
  259.     SetPortTextStyle(itsTextStyle);
  260.     inherited::DrawRangeOfCells(startCell, stopCell, aRect);
  261. }
  262.  
  263. //================================================================================================
  264. void TDiscListView::HighlighOneCell(GridCell aCell, HLState fromHL, HLState toHL)
  265. {
  266.     VRect vr;
  267.     CellToVRect(aCell, vr);
  268.     CRect r;
  269.     ViewToQDRect(vr, r);
  270.     r.top += kSeparatorHeight - 1; // -1 ??
  271. //    r.bottom -= 1;
  272.     PenNormal();
  273.     PenMode(patXor);
  274.     UseSelectionColor();
  275.     switch (fromHL + toHL)
  276.     {
  277.         case hlOnDim:
  278.         case hlOffOn:
  279.             InvertRect(r);
  280.             break;
  281. /*
  282.         case hlOnDim:
  283.             r.Inset(CPoint(1, 1));
  284.             InvertRect(r);
  285.             break;
  286.  
  287.         case hlOffDim:
  288.             FrameRect(r);
  289.             break;
  290.  
  291.         case hlOffOn:
  292.             InvertRect(r);
  293.             break;
  294. */
  295.     }
  296. }
  297.  
  298. pascal void TDiscListView::HighlightCells(RgnHandle theCells,
  299.                                       HLState fromHL,
  300.                                       HLState toHL)
  301. {
  302.     if (fromHL == toHL)
  303.         return;
  304.     Focus();
  305.     switch (fromHL + toHL)
  306.     {
  307.         case hlOffDim:
  308.         case hlOnDim:
  309.         case hlOffOn:
  310.             {
  311.                 CCellInRegionIterator iter(this, theCells);
  312.                 for (GridCell aCell = iter.FirstCell(); iter.More(); aCell = iter.NextCell())
  313.                     HighlighOneCell(aCell, fromHL, toHL);
  314.             }
  315.             break;
  316.     }
  317. }
  318.  
  319.  
  320. //================================================================================================
  321. Boolean TDiscListView::FindHelp(const VPoint &localPoint, VRect &helpRect, short &balloonVariant)
  322. {
  323.     GridCell aCell = VPointToCell(localPoint);
  324.     CDiscListArticleIterator iter(this, aCell);
  325.     CPoint pt = localPoint.ToPoint();
  326.     for (long id = iter.FirstArticleID(); iter.More(); id = iter.NextArticleID())
  327.     {
  328.         CRect subjectRect, statusRect, authorRect;
  329.         iter.GetArticleVRects(subjectRect, statusRect, authorRect);
  330.         if (pt.v < subjectRect.top)
  331.         {
  332.             helpRect.left = 0;
  333.             helpRect.right = fSize.h;
  334.             helpRect.top = 0;
  335.             helpRect.bottom = subjectRect.top;
  336.             fHelpIndex = 1;
  337.             balloonVariant = kHMEnabledItem;
  338.             return false;
  339.         }
  340.  
  341.         if (iter.ArticleIsAvaible())
  342.             balloonVariant = kHMEnabledItem;
  343.         else    
  344.             balloonVariant = kHMDisabledIted())
  345.                 {
  346.                     aCell = LastSelectedCell();
  347.                     aCell.v++;
  348.                 }
  349.                 else
  350.                     aCell = GridCell(1, 1);
  351.                 if (aCell.v <= fNumOfRows)
  352.                 {
  353.                     SelectCell(aCell, false, true, true);
  354.                     ScrollSelectionIntoView(kRedraw);
  355.                     Focus();
  356.                     Update();
  357.                 }
  358.             }
  359.             break;
  360.  
  361.         case chBackspace:
  362.             SetEmptySelection(kRedraw); // should be KILL one day
  363.             break;
  364.             
  365.  
  366.         default:
  367.             inherited::DoKeyEvent(event);
  368.     }
  369. }
  370.  
  371. pascal void TDiscListView::DoMouseCommand(VPoint &theMouse,
  372.                                                         TToolboxEvent *event, CPoint /* hysteresis */ )
  373. {
  374.     GridCell aCell;
  375.     if (IdentifyPoint(theMouse, aCell) == badChoice)
  376.         return;
  377.     if (event->fClickCount > 1 && IsAnyCellSelected())
  378.         OpenSelection();
  379.     else // not double-click
  380.     {
  381.         TStickySelectCommand *aCommand = new TStickySelectCommand();
  382.         aCommand->IStickySelectCommand(this, theMouse, event->IsShiftKeyPressed(), event->IsCommandKeyPressed()); 
  383.         PostCommand(aCommand);
  384.     }
  385. }
  386.  
  387.  
  388. pascal void TDiscListView::DoMenuCommand(CommandNumber aCommandNumber)
  389. {
  390.     if (!IsEnabled())
  391.     {
  392.         inherited::DoMenuCommand(aCommandNumber);
  393.         return;
  394.     }
  395.     switch (aCommandNumber)
  396.     {
  397.         case cShowAllDiscussions:
  398.             if (fDiscToShow != kShowAllDiscs)
  399.             {
  400.                 fDiscToShow = kShowAllDiscs;
  401.                 UpdateList();
  402.             }
  403.             break;
  404.  
  405.         case cShowOnlyTodayDiscussions:
  406.             if (fDiscToShow != kShowTodaysDiscs)
  407.             {
  408.                 fDiscToShow = kShowTodaysDiscs;
  409.                 UpdateList();
  410.             }
  411.             break;
  412.  
  413.         case cShowDiscsWithUnreadArticles:
  414.             if (fDiscToShow != kShowDiscsWithUnreadArticles)
  415.             {
  416.                 fDiscToShow = kShowDiscsWithUnreadArticles;
  417.                 UpdateList();
  418.             }
  419.             break;
  420.  
  421.         case cShowDiscsWithNewArticles:
  422.             if (fDiscToShow != kShowDiscsWithNewArticles)
  423.             {
  424.                 fDiscToShow = kShowDiscsWithNewArticles;
  425.                 UpdateList();
  426.             }
  427.             break;
  428.  
  429.         case cSave:
  430.         case cSaveAs:
  431.         case cSaveCopy:
  432.             {
  433.                 TSaveArticlesCommand *aCommand = new TSaveArticlesCommand();
  434.                 aCommand->ISaveArticlesCommand(cSaveAs, fDoc, GetListOfSelectedArticles());
  435.                 gApplWideThreads->ExecuteCommand(aCommand, "TSaveArticlesCommand (TDiscListView)");
  436.             }
  437.             break;
  438.             
  439.         case cExtractBinaries:
  440.             ExtractBinaries(cExtractBinaries, fDoc, GetListOfSelectedArticles());
  441.             break;
  442.         
  443.         case cPostNewDiscussion:
  444.             TCreateNewDiscussionCommand *command = new TCreateNewDiscussionCommand();
  445.             command->ICreateNewDiscussionCommand(fDoc);
  446.             PostCommand(command);
  447.             break;
  448.             
  449.         case cMarkThreadAsNew:
  450.             MarkSelectionAs(kArticleNew);
  451.             break;
  452.             
  453.         case cMarkThreadAsSeen:
  454.             MarkSelectionAs(kArticleSeen);
  455.             break;
  456.             
  457.         case cMarkThreadAsRead:
  458.             MarkSelectionAs(kArticleRead);
  459.             break;
  460.  
  461.         default:
  462.             {
  463.                 StandardGridViewTextStyle gvts = fGridViewTextStyle;
  464.                 if (gNewsAppl->HandleFontMenu(aCommandNumber, gvts.fTextStyle))
  465.                 {
  466.                     CalcStandardGridViewFont(gvts);
  467.                     fGridViewTextStyle = gvts;
  468.                     gPrefs->SetTextStylePrefs('TSdi', gvts.fTextStyle);
  469.                     ChangedFont();
  470.                 }
  471.                 else
  472.                     inherited::DoMenuCommand(aCommandNumber);
  473.             }
  474.     }
  475. }
  476.  
  477. pascal void TDiscListView::DoSetupMenus()
  478. {
  479.     Boolean lowSpace = MemSpaceIsLow();
  480.     gNewsAppl->EnableFontMenu(fGridViewTextStyle.fTextStyle);
  481.     Boolean gotSelection = IsAnyCellSelected();
  482.     Enable(cExtractBinaries, !lowSpace && gotSelection);
  483.     if (gPrefs->GetBooleanPrefs('BiAs'))
  484.         SetMenuState(cExtractBinaries,    kDynamicMenuItemNames, kExtractAsMenuItemText, kExtractAsMultipleAsMenuItemText, IsOptionKeyDown());
  485.     else
  486.         SetMenuState(cExtractBinaries,    kDynamicMenuItemNames, kExtractMenuItemText, kExtractAsMultipleMenuItemText, IsOptionKeyDown());
  487.  
  488.     Enable(cMarkThreadAsNew, gotSelection);
  489.     Enable(cMarkThreadAsSeen, gotSelection);
  490.     Enable(cMarkThreadAsRead, gotSelection);
  491.  
  492.     Enable(cSelectAll, true);
  493.  
  494.     Enable(cPostNewDiscussion, !lowSpace);
  495.  
  496.     EnableCheck(cShowAllDiscussions, true, fDiscToShow == kShowAllDiscs);
  497.     EnableCheck(cShowOnlyTodayDiscussions, true, fDiscToShow == kShowTodaysDiscs);
  498.     EnableCheck(cShowDiscsWithUnreadArticles, true, fDiscToShow == kShowDiscsWithUnreadArticles);
  499.     EnableCheck(cShowDiscsWithNewArticles, true, fDiscToShow == kShowDiscsWithNewArticles);
  500.  
  501.     inherited::DoSetupMenus();
  502.     Enable(cSave, gotSelection);
  503.     Enable(cSaveAs, false);
  504.     Enable(cSaveCopy, gotSelection);
  505.     Enable(cRevert, false);
  506. }
  507.